/* based on https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecd */
Shiny.addCustomMessageHandler("dendrogram_values", function(message) {

    var dataset = message[0];
    var bardata = message[1];
    var radardata = message[2];

    var k = 0;

    // Set the dimensions and margins of the diagram
    var margin = {top: 20, right: 90, bottom: 30, left: 90},
	width = window.innerWidth - margin.left - margin.right,
	height = window.innerHeight - margin.top - margin.bottom;

    // scales for barchart
    var xScale = d3.scaleBand()
	.domain(d3.range(bardata[0].value.length))
	.range([0, width * 0.55])
	.paddingInner(0.5);

    var yScale = d3.scaleLinear()
	.domain([0, d3.max(bardata[0].value)])
	.range([0, 100]);

    // We can freely modify this scale
    var yScaleb = d3.scaleLinear()
	.domain([0, d3.max(bardata[0].value)])
	.range([0, 100]);

    //Radar chart configuration
    var radarChartOptions = {
	w: width * 0.1,
	h: height * 0.1,
	labelFactor: 1.25,
	opacityArea: 0.20,
	strokeWidth: 2,
    };

    var maxValue = d3.max(radardata[0].value, function(d) {
	return d.value;
    });

    var allAxis = (radardata[0].value.map(function(d) {
	return d.axis;
    }));

    var total = allAxis.length,
	radius = Math.min(radarChartOptions.w/4, radarChartOptions.h/4),
	angleSlice = Math.PI * 2 / total;

    //Scale for the radius
    var rScale = d3.scaleLinear()
    	.domain([0, maxValue])
	.range([0, radius]);
    //End radar chart configuration

    //Create an area to display information about glyph
    d3.select("body")
	.append("div")
	.attr("id", "tooltip_area")
	.style("position", "absolute")
	.style("left", width/20 + "px")
	.style("top", height/10 + "px")
	.style("z-index", "10")
	.style("visibility", "hidden")
	.style("color", "white")
	.style("padding", "8px")
	.style("background-color", "rgba(0, 0, 0, 0.75)")
	.style("border-radius", "6px")
	.style("font", "20px sans-serif")
	.text("tooltip");

    // append the svg object to the area reserved for the dendrogram
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var dendrogram_plot = d3.select("#dendrogram_area").append("svg")
	.attr("width", width + margin.right + margin.left)
	.attr("height", height + margin.top + margin.bottom)
	.append("g")
	.attr("transform", "translate("
              + margin.left + "," + margin.top + ")");


    var i = 0,
	duration = 750,
	root;

    // declares a tree layout and assigns the size
    var dendrogram = d3.cluster().size([height, width * 0.4]);

    // Assigns parent, children, height, depth
    root = d3.hierarchy(dataset, function(d) { return d.children; });
    root.x0 = height / 2;
    root.y0 = 0;

    // Collapse after the second level
    root.children.forEach(collapse);

    update(root);

    //By default show bars and radars only on last level
    toggleBars(root);
    toggleRadars(root);

    // Collapse the node and all it's children
    function collapse(d) {
	if(d.children) {
	    d._children = d.children;
	    d._children.forEach(collapse);
	    d.children = null;
	}
    }

    function update(source) {

	// Assigns the x and y position for the nodes
	var dataset = dendrogram(root);

	// Compute the new tree layout.
	var nodes = dataset.descendants(),
	    links = dataset.descendants().slice(1);

	// ****************** Nodes section ***************************
	//nodes.eachAfter(function(d) { d.y = d.depth * 180; });
	// Update the nodes...
	var node = dendrogram_plot.selectAll('g.node')
	    .data(nodes, function(d) {return d.id || (d.id = ++i); });

	// Enter any new modes at the parent's previous position.
	var nodeEnter = node.enter().append('g')
	    .attr('class', 'node')
	    .attr('id', function(d) {
		return "node-" + (d.id -1);
	    })
	    .attr("transform", function(d) {
		return "translate(" + source.y0 + "," + source.x0 + ")";
	    })
	    .on('click', click)
	    .on('wheel', reScaleBars)
	    .on('auxclick', resetBars);

	// Add Circle for the nodes
	nodeEnter.append('circle')
	    .attr('class', 'node')
	    .attr('r', 1e-6)
	    .style("fill", function(d) {
		return d._children ? "lightsteelblue" : "#fff";
	    });

	// Add labels for the nodes
	nodeEnter.append('text')
	    .attr("dy", ".35em")
	    .attr("x", function(d) {
		//return d.children || d._children ? -13 : 13;
		return -13;
	    })
	    .attr("text-anchor", function(d) {
		//return d.children || d._children ? "end" : "start";
		return "end";
	    })
	    .text(function(d) { return d.data.name; });

	// Add barcharts to nodes
	nodeEnter
	    .selectAll("rect")
	    .data(function(d) {
		if (d.data.name == "Brasil") {
		    return bardata[0].value;
		}

		for (var i = 1; i < bardata.length; i++) {
		    if (d.data.name == bardata[i].name[1]) {
			if (d.ancestors()[1].data.name == bardata[i].name[0]) {
			    return bardata[i].value;
			}
		    }
		}

		return 0;
	    })
	    .enter()
	    .append("rect")
	    .classed("bars", true)
	    .attr("x", function(d, i) {
		return 13 + xScale(i);
	    })
	    .attr("y", function(d) {
		return 13 -yScale(d);
	    })
	    .attr("width", xScale.bandwidth())
	    .attr("height", function(d) {
		return yScale(d);
	    })
	    .attr("fill", "blue");


	// Add radar charts to nodes
	radarBuild = nodeEnter
	    .append("svg")
	    .attr("width",  width)
	    .attr("height", height/8)
	    .attr("transform", "translate(" + (0) + "," + (-50) + ")")
	    .attr("class", "radar")
	    .append("g")
	    .attr("transform", "translate(" + (50 + xScale(365)) + "," + (50) + ")")
	    .on('mouseover', showToolTip)
	    .on('mouseout', hideToolTip);

	var axisGrid = radarBuild.append("g").attr("class", "axisWrapper");

	//Create the straight lines radiating outward from the center
	/*var axis = axisGrid.selectAll(".axis")
	    .data(allAxis)
	    .enter()
	    .append("g")
	    .attr("class", "axis");*/
	//Append the lines
	/*axis.append("line")
	    .attr("x1", 0)
	    .attr("y1", 0)
	    .attr("x2", function(d, i) {
		return rScale(maxValue) * Math.cos(angleSlice*i - Math.PI/2);
	    })
	    .attr("y2", function(d, i) {
		return rScale(maxValue) * Math.sin(angleSlice*i - Math.PI/2);
	    })
	    .attr("class", "radarLine")
	    .style("stroke", "#CDCDCD")
	    .style("stroke-width", "2px")
	    .style("stroke-dasharray", "5,5");*/

	//Append the labels at each axis
	/*axis.append("text")
	    .attr("class", "radarLegend")
	    .style("font-size", "8px")
	    .attr("text-anchor", "middle")
	    .attr("dy", "0.35em")
	    .attr("x", function(d, i) {
		return rScale(maxValue*1.1 * radarChartOptions.labelFactor) * Math.cos(angleSlice*i - Math.PI/2);
	    })
	    .attr("y", function(d, i) {
		return rScale(maxValue*1.1 * radarChartOptions.labelFactor) * Math.sin(angleSlice*i - Math.PI/2);
	    })
	    .text(function(d){return d;});*/

	//The radial line function
	var radarLine = d3.lineRadial()
	    .curve(d3.curveLinearClosed)
	    .angle(function(d, i) {return i * angleSlice; })
	    .radius(function(d) {
		return rScale(d.value);
	    });

	//Create a wrapper for the blobs
	var blobWrapper = radarBuild.selectAll(".radarWrapper")
	    .data(function(d) {
		if (d.data.name == "Brasil") {
		    return [radardata[0].value];
		}

		for (var i = 1; i < radardata.length; i++) {
		    if (d.data.name == radardata[i].name[1]) {
			if (d.ancestors()[1].data.name == radardata[i].name[0]) {
			    return [radardata[i].value];
			}
		    }
		}

		return 0;
	    })
	    .enter()
	    .append("g")
	    .attr("class", "radarWrapper");

	//Append the backgrounds
	blobWrapper
	    .append("path")
	    .attr("d", function() {
		maxValue = d3.max(d3.select(this).data()[0], function(v) {
		    return v.value;
		});
		rScale
		    .domain([0, maxValue]);
		return radarLine(d3.select(this).data()[0]);
	    })
	    .attr("class", "radarArea")
	    .style("fill", "#EDC951")
	    .style("fill-opacity", radarChartOptions.opacityArea);

	//Create the outlines
	blobWrapper.append("path")
	    .attr("class", "radarStroke")
	    .attr("d", function() {
		maxValue = d3.max(d3.select(this).data()[0], function(v) {
		    return v.value;
		});
		rScale
		    .domain([0, maxValue]);
		return radarLine(d3.select(this).data()[0]);
	    })
	    .style("stroke-width", radarChartOptions.strokeWidth + "px")
	    .style("stroke", "black")
	    .style("fill", "none");

	// UPDATE
	var nodeUpdate = nodeEnter.merge(node);

	// Transition to the proper position for the node
	nodeUpdate.transition()
	    .duration(duration)
	    .attr("transform", function(d) {
		return "translate(" + d.y + "," + d.x + ")";
	    });

	// Update the node attributes and style
	nodeUpdate.select('circle.node')
	    .attr('r', 10)
	    .style("fill", function(d) {
		return d._children ? "lightsteelblue" : "#fff";
	    })
	    .attr('cursor', 'pointer');


	// Remove any exiting nodes
	var nodeExit = node.exit().transition()
	    .duration(duration)
	    .attr("transform", function(d) {
		return "translate(" + source.y + "," + source.x + ")";
	    })
	    .remove();

	// On exit reduce the node circles size to 0
	nodeExit.select('circle')
	    .attr('r', 1e-6);

	// On exit reduce the opacity of text labels
	nodeExit.select('text')
	    .style('fill-opacity', 1e-6);

	// ****************** links section ***************************

	// Update the links...
	var link = dendrogram_plot.selectAll('path.link')
	    .data(links, function(d) { return d.id; });

	// Enter any new links at the parent's previous position.
	var linkEnter = link.enter().insert('path', "g")
	    .attr("class", "link")
	    .attr('d', function(d){
		var o = {x: source.x0, y: source.y0};
		return diagonal(o, o);
	    });

	// UPDATE
	var linkUpdate = linkEnter.merge(link);

	// Transition back to the parent element position
	linkUpdate.transition()
	    .duration(duration)
	    .attr('d', function(d){ return diagonal(d, d.parent); });

	// Remove any exiting links
	var linkExit = link.exit().transition()
	    .duration(duration)
	    .attr('d', function(d) {
		var o = {x: source.x, y: source.y};
		return diagonal(o, o);
	    })
	    .remove();

	// Store the old positions for transition.
	nodes.forEach(function(d){
	    d.x0 = d.x;
	    d.y0 = d.y;
	});

	// Creates a curved (diagonal) path from parent to the child nodes
	function diagonal(s, d) {

	    path = `M ${s.y} ${s.x}
            C ${(s.y + d.y) / 2} ${s.x},
              ${(s.y + d.y) / 2} ${d.x},
              ${d.y} ${d.x}`;

	    return path;
	}

	// Toggle children on click.
	function click(d) {
	    //has children, so close them
	    if (d.children) {
		d._children = d.children;
		d.children = null;
		//update(d);
	    } else {
		//dont have children, so open them
		d.children = d._children;
		d._children = null;
		//update(d);
	    }
	    update(d);
	    toggleBars(d);
	    toggleRadars(d);
	}
    }

    function toggleBars(d) {
	// show bars only on last level
	if (d.children) {
	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .bars")
		.attr("fill", "none");

	    d.children.forEach(toggleBars);
	} else {
	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .bars")
		.attr("fill", "blue");
	}
    }

    function toggleRadars(d) {
	// show bars only on last level
	if (d.children) {
	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarArea")
		.style("fill", "none");

	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarLegend")
		.style("fill", "none");

	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarStroke")
		.style("stroke", "none");

	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarLine")
	    	.style("stroke", "none");

	    d.children.forEach(toggleRadars);
	} else {
	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarArea")
		.style("fill", "#EDC951");

	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarLegend")
		.style("fill", "black");

	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarStroke")
		.style("stroke", "black");

	    dendrogram_plot.selectAll("#node-" + (d.id -1) + " .radarLine")
	    	.style("stroke", "#CDCDCD");
	}
    }

    var yCap = 100;

    var current_node = 0;

    function updateScale(step) {
	yCap = yCap + step;
	yScaleb
	    .range([0, yCap]);
    }

    function resetScale() {
	yScaleb
	    .range([0, 100]);
    }

    function reScaleBars(d) {
	if (current_node != (d.id -1)) {
	    resetScale();
	    yCap = 100;
	    current_node = d.id -1;
	}

	if (d3.event.deltaY < 0) {
	    updateScale(20);
	} else {
	    updateScale(-20);
	}

	drawBars(d);
    }

    function resetBars(d) {

	resetScale();
	yCap = 100;
	current_node = d.id -1;

	drawBars(d);

    }

    function drawBars(d) {

	dendrogram_plot.selectAll("#node-" + (d.id -1) + " .bars")
	    .data(function() {
		if (d.data.name == "Brasil") {
		    return bardata[0].value;
		}

		for (var i = 1; i < bardata.length; i++) {
		    if (d.data.name == bardata[i].name[1]) {
			if (d.ancestors()[1].data.name == bardata[i].name[0]) {
			    return bardata[i].value;
			}
		    }
		}

		return 0;
	    })
	    .attr("x", function(d, i) {
		return 13 + xScale(i);
	    })
	    .attr("y", function(d) {
		return 13 -yScaleb(d);
	    })
	    .attr("width", xScale.bandwidth())
	    .attr("height", function(d) {
		return yScaleb(d);
	    });
    }

    function showToolTip(d) {

	var tooltip = d3.select("#tooltip_area");

	var text = "";

	if (d.data.name == "Brasil") {

	    for(var j = 0; j < total; j++) {
		text = text + radardata[0].value[j].axis + ": " + radardata[0].value[j].value + "<br/>";
	    }

	    tooltip.html(d.data.name + "<br/>" + text);
	    tooltip.transition();
	    return tooltip.style("visibility", "visible").style("opacity", 1);
	}

	for (var i = 1; i < radardata.length; i++) {
	    if (d.data.name == radardata[i].name[1]) {
		if (d.ancestors()[1].data.name == radardata[i].name[0]) {

		    for(var k = 0; k < total; k++) {
			if(radardata[i].value[k]) {
			    text = text + radardata[i].value[k].axis + ": " + radardata[i].value[k].value + "<br/>";
			}
		    }
		    tooltip.html(d.data.name + "<br/>" + text);
		    tooltip.transition();
		    return tooltip.style("visibility", "visible").style("opacity", 1);
		}
	    }
	}
	return 0;
    }

    function hideToolTip(d) {

	return d3.select("#tooltip_area").style("visibility", "hidden");
    }

});
